package io.github.echarts.model.geometry;

/**
 * 表示三次贝塞尔曲线路径片段
 * 对应SVG路径中的C命令
 */
public class CurveTo implements PathSegment {
    
    /**
     * 第一个控制点
     */
    private final Point control1;
    
    /**
     * 第二个控制点
     */
    private final Point control2;
    
    /**
     * 终点
     */
    private final Point end;
    
    /**
     * 创建CurveTo路径片段
     * 
     * @param control1 第一个控制点
     * @param control2 第二个控制点
     * @param end 终点
     */
    public CurveTo(Point control1, Point control2, Point end) {
        if (control1 == null || control2 == null || end == null) {
            throw new IllegalArgumentException("控制点和终点不能为null");
        }
        this.control1 = control1;
        this.control2 = control2;
        this.end = end;
    }
    
    /**
     * 创建CurveTo路径片段
     * 
     * @param c1x 第一个控制点X坐标
     * @param c1y 第一个控制点Y坐标
     * @param c2x 第二个控制点X坐标
     * @param c2y 第二个控制点Y坐标
     * @param x 终点X坐标
     * @param y 终点Y坐标
     */
    public CurveTo(double c1x, double c1y, double c2x, double c2y, double x, double y) {
        this(new Point(c1x, c1y), new Point(c2x, c2y), new Point(x, y));
    }
    
    /**
     * 获取第一个控制点
     * 
     * @return 第一个控制点
     */
    public Point getControl1() {
        return control1;
    }
    
    /**
     * 获取第二个控制点
     * 
     * @return 第二个控制点
     */
    public Point getControl2() {
        return control2;
    }
    
    /**
     * 获取终点
     * 
     * @return 终点
     */
    public Point getEnd() {
        return end;
    }
    
    @Override
    public PathSegmentType getType() {
        return PathSegmentType.CURVE_TO;
    }
    
    @Override
    public String toSvgPathData() {
        return "C" + control1.getX() + "," + control1.getY() + " " +
               control2.getX() + "," + control2.getY() + " " +
               end.getX() + "," + end.getY();
    }
    
    @Override
    public Rectangle getBounds(Point startPoint) {
        if (startPoint == null) {
            // 如果没有起始点，只能近似估计边界
            return approximateBounds();
        }
        
        // 为了准确计算贝塞尔曲线的边界，我们需要寻找曲线上的极值点
        // 这通常需要求解曲线的导数为0的点，非常复杂
        // 这里我们使用一个简化的方法：计算包含所有控制点和端点的矩形
        double minX = Math.min(Math.min(Math.min(startPoint.getX(), control1.getX()), control2.getX()), end.getX());
        double minY = Math.min(Math.min(Math.min(startPoint.getY(), control1.getY()), control2.getY()), end.getY());
        double maxX = Math.max(Math.max(Math.max(startPoint.getX(), control1.getX()), control2.getX()), end.getX());
        double maxY = Math.max(Math.max(Math.max(startPoint.getY(), control1.getY()), control2.getY()), end.getY());
        
        return new Rectangle(minX, minY, maxX - minX, maxY - minY);
    }
    
    /**
     * 近似估计贝塞尔曲线的边界
     * 当没有起始点信息时使用
     * 
     * @return 近似的边界矩形
     */
    private Rectangle approximateBounds() {
        double minX = Math.min(Math.min(control1.getX(), control2.getX()), end.getX());
        double minY = Math.min(Math.min(control1.getY(), control2.getY()), end.getY());
        double maxX = Math.max(Math.max(control1.getX(), control2.getX()), end.getX());
        double maxY = Math.max(Math.max(control1.getY(), control2.getY()), end.getY());
        
        return new Rectangle(minX, minY, maxX - minX, maxY - minY);
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        CurveTo curveTo = (CurveTo) o;
        
        if (!control1.equals(curveTo.control1)) return false;
        if (!control2.equals(curveTo.control2)) return false;
        return end.equals(curveTo.end);
    }
    
    @Override
    public int hashCode() {
        int result = control1.hashCode();
        result = 31 * result + control2.hashCode();
        result = 31 * result + end.hashCode();
        return result;
    }
    
    @Override
    public String toString() {
        return "CurveTo{" +
                "control1=" + control1 +
                ", control2=" + control2 +
                ", end=" + end +
                '}';
    }
} 